from flask_restplus import Resource, Namespace, fields, marshal, reqparse, Model
from common.decorators import catch_error
from app.user import service
from app.user.decorators import token_required
from common.responses import ok, created
from flask import g
from common import constant
from app.user.controller import simple_user_model
from middleware.redis import verify_phone_captcha
from common import errors
from app.user.model import User
from app.user.model import BlackList

api = Namespace('auth', path='/auth')

auth_user_model = simple_user_model.inherit("auth_user_model", {
    "access": fields.String(description='access'),
})
# ---------- model end -----------


register_parser = api.parser()
register_parser.add_argument('company_name', help='company_name')
register_parser.add_argument('username', help='username')
register_parser.add_argument('password', required=True, help='password')
register_parser.add_argument('phone', required=True, help='phone')
register_parser.add_argument('email', help='email')
register_parser.add_argument('captcha', required=True, help='captcha')


class RegisterResource(Resource):
    @catch_error
    @api.expect(register_parser)
    def post(self):
        """注册"""
        args = register_parser.parse_args()
        captcha = args.pop("captcha")
        # 手机号，验证码校验
        # if not verify_phone_captcha(args.get("phone"), captcha):
        #     raise errors.BadRequestError('验证码不正确')

        # # 默认生成 公司名称 和用户名
        token = service.register(**args)
        return created(data={
            "Authorization": token,
        }, message='注册成功')


login_parser = api.parser()
login_parser.add_argument('type', type=str, help='登录类型', required=True,
                          choices=[constant.LoginType.ACCOUNT, constant.LoginType.PHONE])
login_parser.add_argument('username', type=str, help='用户名或者手机号')
login_parser.add_argument('password', type=str, help='密码')
login_parser.add_argument('phone', type=str, help='手机号')
login_parser.add_argument('captcha', type=str, help='验证码')


class LoginResource(Resource):
    @catch_error
    @api.expect(login_parser)
    def post(self):
        """登录"""
        args = login_parser.parse_args()

        if args.get('type') == constant.LoginType.ACCOUNT:
            # 先拿用户名匹配手机号
            username = args.get("username")
            if service.check_phone_number(username):
                user = User.query.filter_by(phone=username).first()
            else:
                user = User.query.filter_by(username=username).first()
            if not user:
                raise errors.NotMatchOrUserDoesNotExistError
            # 检查密码
            token = user.login_get_token(password=args.get("password"))
        elif args.get('type') == constant.LoginType.PHONE:
            phone = args.get("phone")
            captcha = args.get("captcha")
            if not service.check_phone_number(phone):
                raise errors.BadRequestError('手机号错误')
            user = User.query.filter_by(phone=phone).first()
            if not user:
                raise errors.NotMatchOrUserDoesNotExistError
            # 检查验证码
            if not verify_phone_captcha(phone, captcha):
                raise errors.BadRequestError('验证码不正确')
            token = user.generate_token()
        else:
            raise errors.BadRequestError('错误登录类型')
        # user.access = 'admin'
        return ok(data={
            "Authorization": token,
            "user": marshal(user, auth_user_model),
            # 'status': 'ok',
            'type': args.get('type')
        }, message="登录成功")


class LogoutResource(Resource):
    @catch_error
    @token_required
    def get(self):
        """登出"""
        # 获取token
        blacklist = BlackList(g.token, g.company_id, commit=True)
        return ok(data={
            'black_list_token': blacklist.token
        }, message='登出成功')


forget_password_parser = reqparse.RequestParser()
forget_password_parser.add_argument('phone', required=True, help='phone')
forget_password_parser.add_argument('password', required=True, help='password')
forget_password_parser.add_argument('captcha', required=True, help='captcha')


class ForgetPasswordResource(Resource):
    @catch_error
    def post(self):
        args = forget_password_parser.parse_args()
        # 手机号
        user = User.query.filter_by(phone=args.get("phone")).first()
        if not user:
            raise errors.BadRequestError('该手机号尚未注册过,请先注册')

        # 手机号，验证码校验
        if not verify_phone_captcha(args.get("phone"), args.pop("captcha")):
            raise errors.BadRequestError('验证码不正确')

        user.update(commit=True, password=args.get("password"))

        token = user.login_get_token(password=args.get("password"))
        return created(data={
            "Authorization": token,
        }, message='重置密码成功')


reset_password_parser = api.parser()
reset_password_parser.add_argument('password', help='密码')


class ResetPasswordResource(Resource):
    @api.expect(reset_password_parser)
    @catch_error
    @token_required
    def post(self):
        """重置密码 非明文传输"""
        args = reset_password_parser.parse_args()
        user = User.query.filter_by(id=g.user_id).first()
        user.update(password=args.get('password'))
        return ok(data={}, message='重置密码成功')


reset_phone_parser = api.parser()
reset_phone_parser.add_argument('phone', help='密码')
reset_phone_parser.add_argument('captcha', help='验证码')


class ResetPhoneResource(Resource):
    @api.expect(reset_password_parser)
    @catch_error
    @token_required
    def post(self):
        """重置密码 非明文传输"""
        args = reset_phone_parser.parse_args()
        user = User.query.filter_by(id=g.user_id).first()

        # 手机号校验
        if User.query.filter_by(phone=args.get("phone")).first():
            raise errors.BadRequestError('该手机号已被注册')
        # 手机号，验证码校验
        # if not verify_phone_captcha(args.get("phone"), args.pop("captcha")):
        #     raise errors.BadRequestError('验证码不正确')

        user.update(phone=args.get('phone'), commit=True)
        return ok(data=marshal(user, simple_user_model), message='重置手机号成功')


send_captcha_parser = reqparse.RequestParser()
send_captcha_parser.add_argument('phone', type=str, help='phone')


# 发送验证码
@api.route('/send_captcha')
class SendCaptchaResource(Resource):
    @catch_error
    @api.expect(send_captcha_parser)
    def post(self):
        """发送验证码"""
        args = send_captcha_parser.parse_args()
        phone = args.get('phone')
        service.send_captcha(phone)
        return ok(data={"phone": phone}, message="send captcha success")


# ---------- 把路由集中在这里，方便查看 -----------
api.add_resource(RegisterResource, '/register')
api.add_resource(LoginResource, '/login')
api.add_resource(LogoutResource, '/logout')
api.add_resource(ForgetPasswordResource, '/forget_password')
api.add_resource(ResetPasswordResource, '/reset_password')  # 登录状态
api.add_resource(SendCaptchaResource, '/send_captcha')
api.add_resource(ResetPhoneResource, '/reset_phone')
